﻿using System.Collections.Generic;
using System.Linq;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;

namespace Leek.Persistence.Azure
{
    public abstract class AzureTableRepository<T, TId, TEntity> : IDomainObjectRepository<T, TId>
        where T : DomainObject<T, TId>
        where TEntity : ITableEntity, new()
    {
        private readonly string _tableName;
        private readonly CloudStorageAccount _cloudStorageAccount;
        private readonly CloudTableClient _cloudTableClient;
        private readonly CloudTable _cloudTable;


        public AzureTableRepository(string tableName)
        {
            _tableName = tableName;

            _cloudStorageAccount = CloudStorageAccount.DevelopmentStorageAccount;

            _cloudTableClient = _cloudStorageAccount.CreateCloudTableClient();

            _cloudTable = _cloudTableClient.GetTableReference(tableName);
            _cloudTable.CreateIfNotExists();
        }


        public void Add(T instance)
        {
            var insert = TableOperation.Insert(ConvertToTableEntity(instance));
            _cloudTable.Execute(insert);
        }

        public void Update(T instance)
        {
            var replace = TableOperation.Replace(ConvertToTableEntity(instance));
            _cloudTable.Execute(replace);
        }

        public void Delete(T instance)
        {
            var delete = TableOperation.Delete(ConvertToTableEntity(instance));
            _cloudTable.Execute(delete);
        }

        public IReadOnlyCollection<T> Load(DomainContext context, FilterExpression filter, int? take = null)
        {
            var query = new TableQuery<TEntity>();
            query.FilterString = AzureTableFilterExpressionBuilder.BuildQuery(filter);
            query.TakeCount = take;

            var matchingRows = _cloudTable.ExecuteQuery(query);

            return matchingRows.Select(entity => ConvertToDomainObject(context, entity))
                .ToList().AsReadOnly();
        }


        protected abstract TEntity ConvertToTableEntity(T instance);

        protected abstract T ConvertToDomainObject(DomainContext context, TEntity entity);
    }
}
